package com.hust.yuqian.utils;

/**
 * Created by mmutuyu on 14-1-10.
 */
public class MatrixTools {
    int [][] asdf;
//
    int [] test;


    /**
     * Hadamard 矩阵实现
     * @return M * M Hadamard 矩阵
     */
    public int[][] Hadamard(int M){
        UsefulData.hadamard_M = M;
        int [][] H = new int[M][M];
        H[0][0] = 1;
        for (int n = 1; n < M; n += n) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    H[i+n][j]   =  H[i][j];
                    H[i][j+n]   =  H[i][j];
                    H[i+n][j+n] = -H[i][j];
                }
            }
        }
        return H;
    }

    /**
     *
     * 这里偷了懒. 省略了密钥. 原因是本实验只是一个检测实验.密钥本来就是已知的.
     * 因此忽略了由密钥构造 HASH 函数来挑选生成 Walsh 矩阵的过程
     * 转而直接截取前部分的 hadamard 矩阵作为 Walsh 矩阵
//     * @param turn 轮数, 共有三轮
     * @param hadamard Hadamard 矩阵
     * @return
     */
    public int[][] Walsh(int [][] hadamard){
        int watermark_height = UsefulData.WATERMARK_HEIGHT;

        int hadamard_m = UsefulData.hadamard_M;

        int begin = 3;

        int [][] result = new int [watermark_height][hadamard_m];

        for(int i = begin; i < begin + watermark_height; i++){
            for(int j = 0; j < hadamard_m; j++){
                result[i-begin][j] = hadamard[i][j];
            }
        }

        return result;

    }


    /**
     *
     * @param C C矩阵
     * @param dct dct 矩阵
     * @return 嵌入了 C 矩阵的 dct 矩阵, 下一步是逆DCT 变换
     */
    public double [][] Imbed(int[][] C, double[][] dct){
        //C 矩阵是N*M, dct 矩阵是M*M
        int n = UsefulData.WATERMARK_HEIGHT;
        int m = UsefulData.image_height;

        int per =(n * m) /  ((m * m) / (8 * 8));//每一个8*8块需要嵌入的信息量

        //在每一个8*8块的 AC 系数中嵌入 per 个数据. C 矩阵读入成为一个一维数组
        int [] c_imbed = new int [n*m];
        for(int i = 0; i < n*m; i++){
            c_imbed[i] = C[i/m][i%m];

        }
        test = c_imbed;

        int per_num = 0;
        for(int i = 0; i < m; i+=8){
            for(int j = 0; j < m; j+=8){

                double [][] temp = new double [8][8];

                for(int u = i; u < i + 8; u++){
                    for(int v = j; v < j + 8; v++){
                        temp[u-i][v-j] = dct[u][v];
                    }
                }

                //JPEG Zig-Zag 之字型读取矩阵
                double [] zigzag_encode;
                zigzag_encode = ZigZag.encode(temp);
                //k=1, 因为8*8矩阵中第一个为 DC 系数, 从第二个开始才是 AC
                for(int k = 1; k <= per; k++){
                    zigzag_encode[k] += c_imbed[per_num * per + k - 1];
                }
                per_num++;
                double [][] zigzag_decode;
                zigzag_decode = ZigZag.decode(zigzag_encode);//8*8的矩阵
                for(int r = 0; r < 8; r++){
                    for(int t = 0; t < 8; t++){
                        dct[r+i][t+j] = zigzag_decode[r][t];
                    }
                }
            }
        }

        return dct;
    }

    /**
     *
     * @param watermarked 有水印的图像的经过 dct 变换的 b 矩阵
//     * @param original 无水印的图像的经过 dct 变换的 b 矩阵
     * @return 原来的 C 矩阵
     */
    public int[][] Extract(double [][] watermarked, double [][] originaldct){


        //C 矩阵是N*M, dct 矩阵是M*M
        int n = UsefulData.WATERMARK_HEIGHT;
        int m = UsefulData.image_height;

        int per =(n * m) /  ((m * m) / (8 * 8));//每一个8*8块需要嵌入的信息量

        int [] c_imbed = new int [n*m];
        int [][] C = new int [n][m];

        int per_num = 0;
        for(int i = 0; i < m; i+=8){
            for(int j = 0; j < m; j+=8){
                double [][] temp_original = new double [8][8];
                double [][] temp_watermarked = new double [8][8];
                for(int r = 0; r < 8; r++){
                    for(int t = 0; t < 8; t++){
                        temp_original[r][t] = originaldct[r+i][t+j];
                        temp_watermarked[r][t] = watermarked[r+i][t+j];
                    }
                }
                double [] zigzag_original = ZigZag.encode(temp_original);
                double [] zigzag_watermarked = ZigZag.encode(temp_watermarked);
                for(int k = 1; k <= per; k++){
                    c_imbed[per_num * per + k - 1] = (int)(zigzag_watermarked[k] - zigzag_original[k]);
                }
                per_num++;
            }
        }

        for(int i = 0; i < n*m; i++){
            C[i/m][i%m] = c_imbed[i];
        }

        return C;
    }

}
